package com.mazaiting.sentinel.handler;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.mazaiting.common.core.domain.result.IResultCode;
import com.mazaiting.common.core.domain.result.Result;
import com.mazaiting.common.core.domain.result.ResultCode;
import com.mazaiting.web.utils.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 流量治理处理器
 * <a href="https://sentinelguard.io/zh-cn/docs/flow-control.html">...</a>
 * 如果使用 gateway 网关的话, FlowException 返回 429
 * @author mazaiting
 * @create_time 2022/4/5 12:14
 */
@Slf4j
@Component
public class SentinelBlockHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        IResultCode resultCode = ResultCode.SENTINEL_ERROR;
        if (e instanceof FlowException flowException) {
            log.error("流量治理-系统限流, 规则: {}, 调用来源: {}", flowException.getRule(), flowException.getRuleLimitApp());
            resultCode = ResultCode.SENTINEL_FLOW_LIMITING;
        } else if (e instanceof DegradeException degradeException) {
            log.error("流量治理-系统功能降级, 规则: {}, 调用来源: {}", degradeException.getRule(), degradeException.getRuleLimitApp());
            resultCode = ResultCode.SENTINEL_DEGRADATION;
        } else if (e instanceof ParamFlowException paramFlowException) {
            log.error("流量治理-热点参数异常, 规则: {}, 调用来源: {}", paramFlowException.getRule(), paramFlowException.getRuleLimitApp());
            resultCode = ResultCode.SENTINEL_HOT_PARAM_FLOW;
        } else if (e instanceof SystemBlockException systemBlockException) {
            log.error("流量治理-系统异常, 规则: {}, 调用来源: {}", systemBlockException.getRule(), systemBlockException.getRuleLimitApp());
            resultCode = ResultCode.SENTINEL_SYSTEM_BLOCK;
        } else if (e instanceof AuthorityException authorityException) {
            log.error("流量治理-授权异常, 规则: {}, 调用来源: {}", authorityException.getRule(), authorityException.getRuleLimitApp());
            resultCode = ResultCode.SENTINEL_AUTHORITY;
        } else {
            log.error("流量治理-未知异常, 规则: {}, 调用来源: {}", e.getRule(), e.getRuleLimitApp());
        }
        // 状态码
        response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        HttpUtil.writeResult(response, Result.failed(resultCode));
    }
}
